/*
 * 
* Copyright (C) 2004-2006  Autodesk, Inc.
* 
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser
* General Public License as published by the Free Software Foundation.
* 
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
* 
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
* 
 */

#include "Pch.h"
#include "DeleteTests.h"

#include <FdoSpatial.h>
#include <FdoCommonFile.h>

#ifdef _WIN32
#define LOCATION L"..\\..\\TestData\\Testing"
#define SCHEMA_NAME L"\\schema.xml"
#else
#define LOCATION L"../../TestData/Testing"
#define SCHEMA_NAME L"/schema.xml"
#endif

CPPUNIT_TEST_SUITE_REGISTRATION (DeleteTests);
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION (DeleteTests, "DeleteTests");

FdoPtr<FdoIConnection> DeleteTests::mConnection;

DeleteTests::DeleteTests (void)
{
    m_schemaNames = FdoStringCollection::Create();
    m_schemaNames->Add(L"TAB");
    m_schemaNames->Add(L"MIF");
}

DeleteTests::~DeleteTests (void)
{
}

void DeleteTests::setUp ()
{
    if (!FdoCommonFile::FileExists (LOCATION))
        FdoCommonFile::MkDir (LOCATION);
    mConnection = MapInfoTests::GetConnection ();
    MapInfoTests::sLocation = LOCATION;
    mConnection->SetConnectionString (L"DefaultFileLocation=" LOCATION);
    CPPUNIT_ASSERT_MESSAGE ("connection state not open", FdoConnectionState_Open == mConnection->Open ());
}

void DeleteTests::tearDown ()
{
    // delete the class, if its there:
    for (FdoInt32 i = 0; i < m_schemaNames->GetCount(); ++i)
    {
        TestCommonSchemaUtil::CleanUpClass(mConnection, m_schemaNames->GetString(i), L"Test");
    }

    mConnection->Close ();

    // On Linux it makes a difference to release here instead of destructor
    // (apparently the global list of files to compress gets trashed too early).
    FDO_SAFE_RELEASE(mConnection.p);

    if (FdoCommonFile::FileExists (LOCATION SCHEMA_NAME))
        FdoCommonFile::Delete (LOCATION SCHEMA_NAME);
    if (FdoCommonFile::FileExists (LOCATION))
        FdoCommonFile::RmDir (LOCATION);
}

void DeleteTests::create_schema (FdoString* schemaName, FdoGeometricType type, bool elevation, bool measure)
{
    // delete the class, if its there:
    TestCommonSchemaUtil::CleanUpClass(mConnection, schemaName, L"Test");

    // create the class
    FdoPtr<FdoFeatureSchema> schema = FdoFeatureSchema::Create (schemaName, L" test schema");
    FdoPtr<FdoClassCollection> classes = schema->GetClasses ();

    FdoPtr<FdoDataPropertyDefinition> featid = FdoDataPropertyDefinition::Create (L"FeatId", L"integer");
    featid->SetDataType (FdoDataType_Int32);
    featid->SetIsAutoGenerated (true);
    featid->SetNullable (false);

    FdoPtr<FdoDataPropertyDefinition> id = FdoDataPropertyDefinition::Create (L"Id", L"integer");
    id->SetDataType (FdoDataType_Decimal);
    id->SetPrecision(10);
    id->SetScale(0);

    FdoPtr<FdoDataPropertyDefinition> street = FdoDataPropertyDefinition::Create (L"Street", L"text");
    street->SetDataType (FdoDataType_String);
    street->SetLength (64);

    FdoPtr<FdoDataPropertyDefinition> area = FdoDataPropertyDefinition::Create (L"Area", L"double");
    area->SetDataType (FdoDataType_Decimal);
    area->SetPrecision (20);
    area->SetScale (8);

    FdoPtr<FdoDataPropertyDefinition> vacant = FdoDataPropertyDefinition::Create (L"Vacant", L"boolean");
    vacant->SetDataType (FdoDataType_Boolean);

    FdoPtr<FdoDataPropertyDefinition> birthday = FdoDataPropertyDefinition::Create (L"Birthday", L"date");
    birthday->SetDataType (FdoDataType_DateTime);

    // build a location geometry property
    FdoPtr<FdoGeometricPropertyDefinition> location = FdoGeometricPropertyDefinition::Create (L"Geometry", L"geometry");
    location->SetGeometryTypes (type);
    location->SetHasElevation (elevation);
    location->SetHasMeasure (measure);

    //// assemble the feature class
    FdoPtr<FdoFeatureClass> feature = FdoFeatureClass::Create (L"Test", L"test class created with apply schema");
    FdoPtr<FdoPropertyDefinitionCollection> properties = feature->GetProperties ();
    FdoPtr<FdoDataPropertyDefinitionCollection> identities = feature->GetIdentityProperties ();
    properties->Add (featid);
    identities->Add (featid);
    properties->Add (id);
    properties->Add (street);
    properties->Add (area);
    properties->Add (vacant);
    properties->Add (birthday);
    properties->Add (location);
    feature->SetGeometryProperty (location);

    // submit the new schema
    classes->Add (feature);
    FdoPtr<FdoIApplySchema> apply = (FdoIApplySchema*)mConnection->CreateCommand (FdoCommandType_ApplySchema);
    apply->SetFeatureSchema (schema);
    apply->Execute ();
    SaveSchema(mConnection);
}

void DeleteTests::del ()
{
    try
    {
        for (FdoInt32 i = 0; i < m_schemaNames->GetCount(); ++i)
        {
            create_schema (m_schemaNames->GetString(i), FdoGeometricType_Point, true, true);
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName (L"Test");
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            // add NULL geometry value:
            FdoPtr<FdoGeometryValue> geometry = FdoGeometryValue::Create ();
            geometry->SetNullValue ();
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 featid;
            featid = -1;
            while (reader->ReadNext ())
            {
                if (-1 != featid)
                    CPPUNIT_FAIL ("too many features inserted");
                featid = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == featid)
                CPPUNIT_FAIL ("too few features inserted");

            // delete all features
            FdoPtr<FdoIDelete> del = (FdoIDelete*)mConnection->CreateCommand (FdoCommandType_Delete);
            del->SetFeatureClassName (L"Test");
            FdoInt32 n = del->Execute ();

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName (L"Test");
            reader = select->Execute ();
            CPPUNIT_ASSERT_MESSAGE ("still features left", !reader->ReadNext ());
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

void DeleteTests::del_geometry ()
{
    try
    {
        for (FdoInt32 i = 0; i < m_schemaNames->GetCount(); ++i)
        {
            create_schema (m_schemaNames->GetString(i), FdoGeometricType_Point, false, false);
            FdoPtr<FdoIInsert> insert = (FdoIInsert*)mConnection->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName (L"Test");
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            // add real geometry value:
            FdoPtr<FdoGeometryValue> geometry = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 999000 -999000 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry);
            values->Add (value);
            FdoPtr<FdoIFeatureReader> reader = insert->Execute ();
            FdoInt32 featid;
            featid = -1;
            while (reader->ReadNext ())
            {
                if (-1 != featid)
                    CPPUNIT_FAIL ("too many features inserted");
                featid = reader->GetInt32 (L"FeatId");
            }
            reader->Close ();
            if (-1 == featid)
                CPPUNIT_FAIL ("too few features inserted");

            // delete all features
            FdoPtr<FdoIDelete> del = (FdoIDelete*)mConnection->CreateCommand (FdoCommandType_Delete);
            del->SetFeatureClassName (L"Test");
            FdoInt32 n = del->Execute ();

            // check by doing a select
            FdoPtr<FdoISelect> select = (FdoISelect*)mConnection->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName (L"Test");
            reader = select->Execute ();
            CPPUNIT_ASSERT_MESSAGE ("still features left", !reader->ReadNext ());
            reader->Close ();
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

void DeleteTests::del_one ()
{
    try
    {
        for (FdoInt32 i = 0; i < m_schemaNames->GetCount(); ++i)
        {
            create_schema (m_schemaNames->GetString(i), FdoGeometricType_Point, false, false);

            // Do insert/delete on 1st connection
            FdoIConnection *mConnection1 = MapInfoTests::GetConnection ();
            MapInfoTests::sLocation = LOCATION;
            mConnection1->SetConnectionString (L"DefaultFileLocation=" LOCATION);
            CPPUNIT_ASSERT_MESSAGE ("connection state not open", FdoConnectionState_Open == mConnection1->Open ());

            // Do select on 2nd connection
            FdoIInsert *insert = (FdoIInsert*)mConnection1->CreateCommand (FdoCommandType_Insert);
            insert->SetFeatureClassName (L"Test");
            FdoPtr<FdoPropertyValueCollection> values = insert->GetPropertyValues ();

            FdoInt32 featids[3];
            int index = 0;

            // feat #1
            FdoPtr<FdoValueExpression> expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"24", FdoDataType_Decimal);
            FdoPtr<FdoPropertyValue> value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'1147 Trafford Drive'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            FdoPtr<FdoGeometryValue> geometry1 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 999000 -999000 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry1);
            values->Add (value);
            FdoIFeatureReader *reader = insert->Execute ();

            while (reader->ReadNext ())
            {
                if (index > 2)
                    CPPUNIT_FAIL ("too many features inserted");
                featids[index++] = reader->GetInt32 (DEFAULT_FEATURE_ID_PROPERTY_NAME);
            }
            reader->Close ();
            reader->Release();

            // feat #2
            values->Clear();
            expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"9191", FdoDataType_Decimal);
            value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'2611 Misener Crescent'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            FdoPtr<FdoGeometryValue> geometry2 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 324.65 7687.0 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry2);
            values->Add (value);
            reader = insert->Execute ();
            while (reader->ReadNext ())
            {
                if (index > 2)
                    CPPUNIT_FAIL ("too many features inserted");
                featids[index++] = reader->GetInt32 (DEFAULT_FEATURE_ID_PROPERTY_NAME);
            }
            reader->Close ();
            reader->Release();

            // feat #3
            values->Clear();
            expression = (FdoValueExpression*)MapInfoTests::ParseByDataType (L"46", FdoDataType_Decimal);
            value = FdoPropertyValue::Create (L"Id", expression);
            values->Add (value);
            expression = (FdoValueExpression*)FdoExpression::Parse (L"'99 Rockcliffe Place'");
            value = FdoPropertyValue::Create (L"Street", expression);
            values->Add (value);
            FdoPtr<FdoGeometryValue> geometry3 = (FdoGeometryValue*)FdoExpression::Parse (L"GEOMFROMTEXT ('POINT XY ( 2828.26 78127.83 )')");
            value = FdoPropertyValue::Create (L"Geometry", geometry3);
            values->Add (value);
            reader = insert->Execute ();
            while (reader->ReadNext ())
            {
                if (index > 2)
                    CPPUNIT_FAIL ("too many features inserted");
                featids[index++] = reader->GetInt32 (DEFAULT_FEATURE_ID_PROPERTY_NAME);
            }
            reader->Close ();
            reader->Release();

            if (2 > index)
                CPPUNIT_FAIL ("too few features inserted");

            int refsi = insert->Release();
            CPPUNIT_ASSERT_MESSAGE ("Leaking insert cmd", refsi == 0);


            ///////////// Delete
            FdoIDelete* del = (FdoIDelete*)mConnection1->CreateCommand (FdoCommandType_Delete);
            del->SetFeatureClassName (L"Test");
            wchar_t buffer[1024];
            swprintf (buffer, ELEMENTS(buffer), L"FID = %d", featids[1]);
            del->SetFilter (FdoPtr<FdoFilter>(FdoFilter::Parse (buffer)));
            FdoInt32 n = del->Execute ();

            // Cleanup conn1
            del->Release();
            mConnection1->Close();
            int refs1 = mConnection1->Release();
            //CPPUNIT_ASSERT_MESSAGE ("Leaking connections1", refs1 == 0);

            // Close/open the static connection in order to force compression NOW
            mConnection->Close();
            FDO_SAFE_RELEASE(mConnection.p); 

            mConnection = MapInfoTests::GetConnection ();
            MapInfoTests::sLocation = LOCATION;
            mConnection->SetConnectionString (L"DefaultFileLocation=" LOCATION);
            CPPUNIT_ASSERT_MESSAGE ("connection state not open", FdoConnectionState_Open == mConnection->Open ());

            ////////////////////
            FdoPtr<FdoFgfGeometryFactory> agf = FdoFgfGeometryFactory::GetInstance();

            // Do select on 2nd connection
            FdoIConnection *mConnection2 = MapInfoTests::GetConnection ();
            MapInfoTests::sLocation = LOCATION;
            mConnection2->SetConnectionString (L"DefaultFileLocation=" LOCATION);
            CPPUNIT_ASSERT_MESSAGE ("connection state not open", FdoConnectionState_Open == mConnection2->Open ());

            // check by doing a select
            FdoISelect *select = (FdoISelect*)mConnection2->CreateCommand (FdoCommandType_Select);
            select->SetFeatureClassName (L"Test");

             FdoIFeatureReader *reader2 = select->Execute ();

            // Check feature #1:
            CPPUNIT_ASSERT_MESSAGE ("not enough features", reader2->ReadNext ());
            CPPUNIT_ASSERT_MESSAGE ("wrong feat id", featids[0] == reader2->GetInt32 (DEFAULT_FEATURE_ID_PROPERTY_NAME));
            CPPUNIT_ASSERT_MESSAGE ("wrong id", 24 == reader2->GetDouble(L"Id"));
            FdoStringP streetVal = reader2->GetString(L"Street");
            CPPUNIT_ASSERT_MESSAGE ("wrong street", streetVal == L"1147 Trafford Drive");
            FdoPtr<FdoByteArray> geomRead1 = reader2->GetGeometry(L"Geometry");
            FdoPtr<FdoByteArray> geomWritten1 = geometry1->GetGeometry();
            FdoPtr<FdoIGeometry> geomRead1B = agf->CreateGeometryFromFgf(geomRead1);
            FdoPtr<FdoIGeometry> geomWritten1B = agf->CreateGeometryFromFgf(geomWritten1);
            CPPUNIT_ASSERT_MESSAGE ("wrong geometry", TestCommonGeomUtil::GeometriesEquivalent(geomRead1B, geomWritten1B));

            // Check feature #3  (it is #2 due to compressing and renumbering)
            CPPUNIT_ASSERT_MESSAGE ("not enough features", reader2->ReadNext ());
            CPPUNIT_ASSERT_MESSAGE ("wrong feat id", featids[1] == reader2->GetInt32 (DEFAULT_FEATURE_ID_PROPERTY_NAME));
            CPPUNIT_ASSERT_MESSAGE ("wrong id", 46 == reader2->GetDouble(L"Id"));
            streetVal = reader2->GetString(L"Street");
            CPPUNIT_ASSERT_MESSAGE ("wrong street", streetVal == L"99 Rockcliffe Place");
            FdoPtr<FdoByteArray> geomRead3 = reader2->GetGeometry(L"Geometry");
            FdoPtr<FdoByteArray> geomWritten3 = geometry3->GetGeometry();
            FdoPtr<FdoIGeometry> geomRead3B = agf->CreateGeometryFromFgf(geomRead3);
            FdoPtr<FdoIGeometry> geomWritten3B = agf->CreateGeometryFromFgf(geomWritten3);
            CPPUNIT_ASSERT_MESSAGE ("wrong geometry", TestCommonGeomUtil::GeometriesEquivalent(geomRead3B, geomWritten3B));

            // Make sure nothing is left:
            CPPUNIT_ASSERT_MESSAGE ("still features left", !reader2->ReadNext ());

            // Cleanup
            reader2->Close ();
            reader2->Release();
            select->Release();
            mConnection2->Close();
            int refs2 = mConnection2->Release();

            //CPPUNIT_ASSERT_MESSAGE ("Leaking connections2", refs2 == 0);
        }
    }
    catch (FdoException* ge) 
    {
        TestCommonFail (ge);
    }
}

